From 3442400e927e34d76f63590576d89f32aaa8cc19 Mon Sep 17 00:00:00 2001 From: Jonathan Dieter Date: Mon, 19 Mar 2018 21:11:51 +0200 Subject: [PATCH] Split multirange parsing into multipart.c Signed-off-by: Jonathan Dieter --- include/zck.h | 4 +- src/lib/dl/dl.c | 374 +++++++++++++---------------------------- src/lib/dl/meson.build | 2 +- src/lib/dl/multipart.c | 242 ++++++++++++++++++++++++++ src/lib/zck_private.h | 9 + src/zck_dl.c | 4 +- 6 files changed, 373 insertions(+), 262 deletions(-) create mode 100644 src/lib/dl/multipart.c diff --git a/include/zck.h b/include/zck.h index 20e3bc5..b141955 100644 --- a/include/zck.h +++ b/include/zck.h @@ -111,12 +111,12 @@ void zck_set_log_level(log_type ll); void zck_dl_global_init(); void zck_dl_global_cleanup(); zckDL *zck_dl_init(); -void zck_dl_free(zckDL *dl); +void zck_dl_free(zckDL **dl); void zck_dl_free_regex(zckDL *dl); int zck_dl_get_header(zckCtx *zck, zckDL *dl, char *url); size_t zck_dl_get_bytes_downloaded(zckDL *dl); size_t zck_dl_get_bytes_uploaded(zckDL *dl); -int zck_dl_range(zckDL *dl, char *url); +int zck_dl_range(zckDL *dl, char *url, int is_chunk); char *zck_dl_get_range(unsigned int start, unsigned int end); int zck_hash_check_full_file(zckCtx *zck, int dst_fd); #endif diff --git a/src/lib/dl/dl.c b/src/lib/dl/dl.c index 879b1dd..6c59ac8 100644 --- a/src/lib/dl/dl.c +++ b/src/lib/dl/dl.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include @@ -41,6 +40,24 @@ return False; \ } +/* Free zckDL regex's used for downloading ranges */ +void zck_dl_free_dl_regex(zckDL *dl) { + if(dl == NULL || dl->priv == NULL) + return; + + if(dl->priv->dl_regex) { + regfree(dl->priv->dl_regex); + free(dl->priv->dl_regex); + dl->priv->dl_regex = NULL; + } + if(dl->priv->end_regex) { + regfree(dl->priv->end_regex); + free(dl->priv->end_regex); + dl->priv->end_regex = NULL; + } +} + +/* Write zeros to tgt->fd in location of tgt_idx */ int zck_dl_write_zero(zckCtx *tgt, zckIndex *tgt_idx) { char buf[BUF_SIZE] = {0}; size_t tgt_data_offset = tgt->preindex_size + tgt->comp_index_size; @@ -59,6 +76,7 @@ int zck_dl_write_zero(zckCtx *tgt, zckIndex *tgt_idx) { } int zck_dl_write(zckDL *dl, const char *at, size_t length) { + VALIDATE(dl); if(dl->write_in_chunk < length) length = dl->write_in_chunk; if(!zck_write(dl->dst_fd, at, length)) @@ -68,6 +86,7 @@ int zck_dl_write(zckDL *dl, const char *at, size_t length) { } int zck_dl_md_write(zckDL *dl, const char *at, size_t length) { + VALIDATE(dl); int wb = 0; if(dl->write_in_chunk > 0) { wb = zck_dl_write(dl, at, length); @@ -82,6 +101,7 @@ int zck_dl_md_write(zckDL *dl, const char *at, size_t length) { } int zck_dl_write_chunk(zckDL *dl) { + VALIDATE(dl); if(dl->chunk_hash == NULL) { zck_log(ZCK_LOG_ERROR, "Chunk hash not initialized\n"); return False; @@ -102,8 +122,9 @@ int zck_dl_write_chunk(zckDL *dl) { return True; } -int zck_dl_multidata_cb(zckDL *dl, const char *at, size_t length) { - if(dl == NULL || dl->info.index.first == NULL) { +int zck_dl_write_range(zckDL *dl, const char *at, size_t length) { + VALIDATE(dl); + if(dl->info.index.first == NULL) { zck_log(ZCK_LOG_ERROR, "zckDL index not initialized\n"); return 0; } @@ -150,78 +171,13 @@ int zck_dl_multidata_cb(zckDL *dl, const char *at, size_t length) { } int wb2 = 0; if(dl->write_in_chunk > 0 && wb < length) { - wb2 = zck_dl_multidata_cb(dl, at+wb, length-wb); + wb2 = zck_dl_write_range(dl, at+wb, length-wb); if(wb2 == 0) return 0; } return wb + wb2; } -zckDL *zck_dl_init() { - zckDL *dl = zmalloc(sizeof(zckDL)); - if(!dl) { - zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes for zckDL\n", - sizeof(zckDL)); - return NULL; - } - dl->priv = zmalloc(sizeof(zckDLPriv)); - if(!dl->priv) { - zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes for dl->priv\n", - sizeof(zckDL)); - return NULL; - } - dl->priv->mp = zmalloc(sizeof(zckMP)); - if(!dl->priv->mp) { - zck_log(ZCK_LOG_ERROR, - "Unable to allocate %lu bytes for dl->priv->mp\n", - sizeof(zckMP)); - return NULL; - } - dl->priv->curl_ctx = curl_easy_init(); - if(!dl->priv->curl_ctx) { - zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes for dl->curl_ctx\n", - sizeof(CURL)); - return NULL; - } - return dl; -} - -void zck_dl_free_regex(zckDL *dl) { - if(dl == NULL || dl->priv == NULL) - return; - - if(dl->priv->dl_regex) { - regfree(dl->priv->dl_regex); - free(dl->priv->dl_regex); - dl->priv->dl_regex = NULL; - } - if(dl->priv->hdr_regex) { - regfree(dl->priv->hdr_regex); - free(dl->priv->hdr_regex); - dl->priv->hdr_regex = NULL; - } -} - -void zck_dl_free(zckDL *dl) { - if(!dl) - return; - if(dl->priv) { - if(dl->priv->mp) { - if(dl->priv->mp->buffer) - free(dl->priv->mp->buffer); - free(dl->priv->mp); - } - zck_dl_free_regex(dl); - curl_easy_cleanup(dl->priv->curl_ctx); - free(dl->priv); - } - if(dl->info.first) - zck_range_close(&(dl->info)); - if(dl->boundary) - free(dl->boundary); - free(dl); -} - char *zck_dl_get_range_char(unsigned int start, unsigned int end) { zckRange r = {0}; zckRange *range = &r; @@ -232,191 +188,6 @@ char *zck_dl_get_range_char(unsigned int start, unsigned int end) { return range_header; } -static char *add_boundary_to_regex(const char *regex, const char *boundary) { - char *regex_b = zmalloc(strlen(regex) + strlen(boundary) + 1); - if(regex_b == NULL) { - zck_log(ZCK_LOG_ERROR, - "Unable to reallocate %lu bytes for regular expression\n", - strlen(regex) + strlen(boundary) - 2); - return 0; - } - if(snprintf(regex_b, strlen(regex) + strlen(boundary), regex, - boundary) != strlen(regex) + strlen(boundary) - 2) { - zck_log(ZCK_LOG_ERROR, "Unable to build regular expression\n"); - return 0; - } - return regex_b; -} - - -static int create_regex(regex_t *reg, const char *regex) { - if(regcomp(reg, regex, REG_ICASE | REG_EXTENDED) != 0) { - zck_log(ZCK_LOG_ERROR, "Unable to compile regular expression\n"); - return False; - } - return True; -} - -static size_t extract_multipart(char *b, size_t l, void *dl_v) { - if(dl_v == NULL) - return 0; - zckDL *dl = (zckDL*)dl_v; - if(dl->priv == NULL || dl->priv->mp == NULL) - return 0; - zckMP *mp = dl->priv->mp; - char *buf = b; - int alloc_buf = False; - - /* Add new data to stored buffer */ - if(mp->buffer) { - buf = realloc(mp->buffer, mp->buffer_len + l); - if(buf == NULL) { - zck_log(ZCK_LOG_ERROR, "Unable to reallocate %lu bytes for zckDL\n", - mp->buffer_len + l); - return 0; - } - memcpy(buf + mp->buffer_len, b, l); - l = mp->buffer_len + l; - mp->buffer = NULL; // No need to free, buf holds realloc'd buffer - mp->buffer_len = 0; - alloc_buf = True; - } - - /* If regex hasn't been created, create it */ - if(dl->priv->dl_regex == NULL) { - char *regex = "\r\n--%s\r\ncontent-type:.*\r\n" \ - "content-range: *bytes *([0-9]+) *- *([0-9]+) */.*\r\n\r"; - char *regex_b = add_boundary_to_regex(regex, dl->boundary); - if(regex_b == NULL) - return 0; - dl->priv->dl_regex = zmalloc(sizeof(regex_t)); - if(!create_regex(dl->priv->dl_regex, regex_b)) { - free(regex_b); - return 0; - } - free(regex_b); - } - - char *header_start = buf; - char *i = buf; - while(i) { - char *end = buf + l; - /* If we're in data writing state, then write data until end of buffer - * or end of range, whichever comes first */ - if(mp->state != 0) { - if(i >= end) - break; - size_t size = end - i; - if(mp->length <= size) { - size = mp->length; - mp->length = 0; - mp->state = 0; - header_start = i + size; - } else { - mp->length -= size; - } - if(zck_dl_multidata_cb(dl, i, size) != size) - return 0; - i += size; - continue; - } - - /* If we've reached the end of the buffer without finishing, save it - * and leave loop */ - if(i >= end) { - size_t size = buf + l - header_start; - if(size > 0) { - mp->buffer = malloc(size); - memcpy(mp->buffer, header_start, size); - mp->buffer_len = size; - } - break; - } - - /* Find double newline and replace final \n with \0, so it's a zero- - * terminated string */ - for(char *j=i; j= end) { - i = j+4; - break; - } - if(memcmp(j, "\r\n\r\n", 4) == 0) { - j[3] = '\0'; - break; - } - } - if(i >= end) - continue; - - /* Run regex against download range string */ - regmatch_t match[4] = {0}; - if(regexec(dl->priv->dl_regex, i, 3, match, 0) != 0) { - zck_log(ZCK_LOG_ERROR, "Unable to find multipart download range\n"); - goto end; - } - - /* Get range start from regex */ - size_t rstart = 0; - for(char *c=i + match[1].rm_so; c < i + match[1].rm_eo; c++) - rstart = rstart*10 + (size_t)(c[0] - 48); - - /* Get range end from regex */ - size_t rend = 0; - for(char *c=i + match[2].rm_so; c < i + match[2].rm_eo; c++) - rend = rend*10 + (size_t)(c[0] - 48); - - i += match[0].rm_eo + 1; - zck_log(ZCK_LOG_DEBUG, "Download range: %lu-%lu\n", rstart, rend); - mp->length = rend-rstart+1; - mp->state = 1; - } -end: - if(alloc_buf) - free(buf); - return l; -} - -static size_t get_header(char *b, size_t l, size_t c, void *dl_v) { - if(dl_v == NULL) - return 0; - zckDL *dl = (zckDL*)dl_v; - - if(dl->priv == NULL) - return 0; - - /* Create regex to find boundary */ - if(dl->priv->hdr_regex == NULL) { - char *regex = "boundary *= *([0-9a-fA-F]+)"; - dl->priv->hdr_regex = zmalloc(sizeof(regex_t)); - if(!create_regex(dl->priv->hdr_regex, regex)) - return 0; - } - - /* Copy buffer to null-terminated string because POSIX regex requires null- - * terminated string */ - size_t size = l*c; - char *buf = zmalloc(size+1); - if(buf == NULL) { - zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes for header\n", - size+1); - return 0; - } - buf[size] = '\0'; - memcpy(buf, b, size); - - /* Check whether this header contains the boundary and set it if it does */ - regmatch_t match[2] = {0}; - if(regexec(dl->priv->hdr_regex, buf, 2, match, 0) == 0) { - char *boundary = zmalloc(match[1].rm_eo - match[1].rm_so + 1); - memcpy(boundary, buf + match[1].rm_so, match[1].rm_eo - match[1].rm_so); - zck_log(ZCK_LOG_DEBUG, "Multipart boundary: %s\n", boundary); - dl->boundary = boundary; - } - if(buf) - free(buf); - return l*c; -} - static size_t write_data(void *ptr, size_t l, size_t c, void *dl_v) { if(dl_v == NULL) return 0; @@ -424,7 +195,13 @@ static size_t write_data(void *ptr, size_t l, size_t c, void *dl_v) { size_t wb = 0; dl->dl += l*c; if(dl->boundary != NULL) { - int retval = extract_multipart(ptr, l*c, dl_v); + int retval = zck_multipart_extract(dl, ptr, l*c); + if(retval == 0) + wb = 0; + else + wb = l*c; + } else if(dl->priv->is_chunk) { + int retval = zck_dl_write_range(dl, ptr, l*c); if(retval == 0) wb = 0; else @@ -510,7 +287,15 @@ int zck_dl_copy_src_chunks(zckRangeInfo *info, zckCtx *src, zckCtx *tgt) { return True; } -int zck_dl_range(zckDL *dl, char *url) { +static size_t get_header(char *b, size_t l, size_t c, void *dl_v) { + if(dl_v == NULL) + return 0; + zckDL *dl = (zckDL*)dl_v; + + return zck_multipart_get_boundary(dl, b, c*l); +} + +int zck_dl_range(zckDL *dl, char *url, int is_chunk) { if(dl == NULL || dl->priv == NULL || dl->info.first == NULL) { zck_log(ZCK_LOG_ERROR, "Struct not defined\n"); return False; @@ -521,6 +306,7 @@ int zck_dl_range(zckDL *dl, char *url) { } if(dl->info.segments == 0) dl->info.segments = 1; + dl->priv->is_chunk = is_chunk; char **ra = calloc(sizeof(char*), dl->info.segments); if(!zck_range_get_array(&(dl->info), ra)) { @@ -531,6 +317,13 @@ int zck_dl_range(zckDL *dl, char *url) { for(int i=0; iinfo.segments; i++) { struct curl_slist *header = NULL; + + if(dl->priv->dl_regex != NULL) + zck_dl_free_dl_regex(dl); + if(dl->boundary != NULL) + free(dl->boundary); + + zck_log(ZCK_LOG_DEBUG, "%s\n", ra[i]); header = curl_slist_append(header, ra[i]); curl_easy_setopt(dl->priv->curl_ctx, CURLOPT_URL, url); curl_easy_setopt(dl->priv->curl_ctx, CURLOPT_FOLLOWLOCATION, 1L); @@ -555,6 +348,7 @@ int zck_dl_range(zckDL *dl, char *url) { url); return False; } + zck_dl_free_regex(dl); } free(ra); return True; @@ -580,7 +374,7 @@ int zck_dl_bytes(zckDL *dl, char *url, size_t bytes, size_t start, idx.length = start+bytes-*buffer_len; zck_range_close(&(dl->info)); zck_range_add(&(dl->info), &idx, NULL); - if(!zck_dl_range(dl, url)) + if(!zck_dl_range(dl, url, 0)) return False; zck_range_close(&(dl->info)); *buffer_len = start+bytes; @@ -626,6 +420,7 @@ int zck_zero_bytes(zckDL *dl, size_t bytes, size_t start, size_t *buffer_len) { return True; } +/* Download header */ int zck_dl_get_header(zckCtx *zck, zckDL *dl, char *url) { size_t buffer_len = 0; size_t start = 0; @@ -692,3 +487,68 @@ void zck_dl_global_init() { void zck_dl_global_cleanup() { curl_global_cleanup(); } + +/* Free zckDL header regex used for downloading ranges */ +void zck_dl_free_regex(zckDL *dl) { + if(dl == NULL || dl->priv == NULL) + return; + + zck_dl_free_dl_regex(dl); + if(dl->priv->hdr_regex) { + regfree(dl->priv->hdr_regex); + free(dl->priv->hdr_regex); + dl->priv->hdr_regex = NULL; + } +} + +/* Initialize zckDL. When finished, zckDL *must* be freed by zck_dl_free() */ +zckDL *zck_dl_init() { + zckDL *dl = zmalloc(sizeof(zckDL)); + if(!dl) { + zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes for zckDL\n", + sizeof(zckDL)); + return NULL; + } + dl->priv = zmalloc(sizeof(zckDLPriv)); + if(!dl->priv) { + zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes for dl->priv\n", + sizeof(zckDL)); + return NULL; + } + dl->priv->mp = zmalloc(sizeof(zckMP)); + if(!dl->priv->mp) { + zck_log(ZCK_LOG_ERROR, + "Unable to allocate %lu bytes for dl->priv->mp\n", + sizeof(zckMP)); + return NULL; + } + dl->priv->curl_ctx = curl_easy_init(); + if(!dl->priv->curl_ctx) { + zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes for dl->curl_ctx\n", + sizeof(CURL)); + return NULL; + } + return dl; +} + +/* Free zckDL and set pointer to NULL */ +void zck_dl_free(zckDL **dl) { + if(!*dl) + return; + if((*dl)->priv) { + if((*dl)->priv->mp) { + if((*dl)->priv->mp->buffer) + free((*dl)->priv->mp->buffer); + free((*dl)->priv->mp); + } + zck_dl_free_regex(*dl); + curl_easy_cleanup((*dl)->priv->curl_ctx); + free((*dl)->priv); + } + if((*dl)->info.first) + zck_range_close(&((*dl)->info)); + if((*dl)->boundary) + free((*dl)->boundary); + free(*dl); + *dl = NULL; +} diff --git a/src/lib/dl/meson.build b/src/lib/dl/meson.build index 07a43e7..3e302be 100644 --- a/src/lib/dl/meson.build +++ b/src/lib/dl/meson.build @@ -1 +1 @@ -sources += ['dl/range.c', 'dl/dl.c'] +sources += ['dl/range.c', 'dl/dl.c', 'dl/multipart.c'] diff --git a/src/lib/dl/multipart.c b/src/lib/dl/multipart.c new file mode 100644 index 0000000..09fd4de --- /dev/null +++ b/src/lib/dl/multipart.c @@ -0,0 +1,242 @@ +/* + * Copyright 2018 Jonathan Dieter + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "zck_private.h" + +#define VALIDATE(f) if(!f) { \ + zck_log(ZCK_LOG_ERROR, "zckDL not allocated\n"); \ + return False; \ + } + +static char *add_boundary_to_regex(const char *regex, const char *boundary) { + if(regex == NULL || boundary == NULL) + return NULL; + char *regex_b = zmalloc(strlen(regex) + strlen(boundary) + 1); + if(regex_b == NULL) { + zck_log(ZCK_LOG_ERROR, + "Unable to reallocate %lu bytes for regular expression\n", + strlen(regex) + strlen(boundary) - 2); + return NULL; + } + if(snprintf(regex_b, strlen(regex) + strlen(boundary), regex, + boundary) != strlen(regex) + strlen(boundary) - 2) { + free(regex_b); + zck_log(ZCK_LOG_ERROR, "Unable to build regular expression\n"); + return NULL; + } + return regex_b; +} + +static int create_regex(regex_t *reg, const char *regex) { + if(reg == NULL || regex == NULL) { + zck_log(ZCK_LOG_ERROR, "Regular expression not initialized\n"); + return False; + } + if(regcomp(reg, regex, REG_ICASE | REG_EXTENDED) != 0) { + zck_log(ZCK_LOG_ERROR, "Unable to compile regular expression\n"); + return False; + } + return True; +} + +size_t zck_multipart_extract(zckDL *dl, char *b, size_t l) { + VALIDATE(dl); + if(dl->priv == NULL || dl->priv->mp == NULL) + return 0; + zckMP *mp = dl->priv->mp; + char *buf = b; + int alloc_buf = False; + + /* Add new data to stored buffer */ + if(mp->buffer) { + buf = realloc(mp->buffer, mp->buffer_len + l); + if(buf == NULL) { + zck_log(ZCK_LOG_ERROR, "Unable to reallocate %lu bytes for zckDL\n", + mp->buffer_len + l); + return 0; + } + memcpy(buf + mp->buffer_len, b, l); + l = mp->buffer_len + l; + mp->buffer = NULL; // No need to free, buf holds realloc'd buffer + mp->buffer_len = 0; + alloc_buf = True; + } + + /* If regex hasn't been created, create it */ + if(dl->priv->dl_regex == NULL) { + char *next = "\r\n--%s\r\ncontent-type:.*\r\n" \ + "content-range: *bytes *([0-9]+) *- *([0-9]+) */.*\r\n\r"; + char *end = "\r\n--%s--\r\n\r"; + char *regex_n = add_boundary_to_regex(next, dl->boundary); + if(regex_n == NULL) + return 0; + char *regex_e = add_boundary_to_regex(end, dl->boundary); + if(regex_n == NULL) + return 0; + dl->priv->dl_regex = zmalloc(sizeof(regex_t)); + if(!create_regex(dl->priv->dl_regex, regex_n)) { + free(regex_n); + return 0; + } + free(regex_n); + dl->priv->end_regex = zmalloc(sizeof(regex_t)); + if(!create_regex(dl->priv->end_regex, regex_e)) { + free(regex_e); + return 0; + } + free(regex_e); + } + + char *header_start = buf; + char *i = buf; + while(i) { + char *end = buf + l; + /* If we're in data writing state, then write data until end of buffer + * or end of range, whichever comes first */ + if(mp->state != 0) { + if(i >= end) + break; + size_t size = end - i; + if(mp->length <= size) { + size = mp->length; + mp->length = 0; + mp->state = 0; + header_start = i + size; + } else { + mp->length -= size; + } + if(zck_dl_write_range(dl, i, size) != size) + return 0; + i += size; + continue; + } + + /* If we've reached the end of the buffer without finishing, save it + * and leave loop */ + if(i >= end) { + size_t size = buf + l - header_start; + if(size > 0) { + mp->buffer = malloc(size); + memcpy(mp->buffer, header_start, size); + mp->buffer_len = size; + } + break; + } + + /* Find double newline and replace final \n with \0, so it's a zero- + * terminated string */ + for(char *j=i; j= end) { + i = j+4; + break; + } + if(memcmp(j, "\r\n\r\n", 4) == 0) { + j[3] = '\0'; + break; + } + } + if(i >= end) + continue; + + /* Run regex against download range string */ + regmatch_t match[4] = {0}; + if(regexec(dl->priv->dl_regex, i, 3, match, 0) != 0) { + if(regexec(dl->priv->end_regex, i, 3, match, 0) != 0) + zck_log(ZCK_LOG_ERROR, "Unable to find multipart download range\n"); + goto end; + } + + /* Get range start from regex */ + size_t rstart = 0; + for(char *c=i + match[1].rm_so; c < i + match[1].rm_eo; c++) + rstart = rstart*10 + (size_t)(c[0] - 48); + + /* Get range end from regex */ + size_t rend = 0; + for(char *c=i + match[2].rm_so; c < i + match[2].rm_eo; c++) + rend = rend*10 + (size_t)(c[0] - 48); + + i += match[0].rm_eo + 1; + zck_log(ZCK_LOG_DEBUG, "Download range: %lu-%lu\n", rstart, rend); + mp->length = rend-rstart+1; + mp->state = 1; + } +end: + if(alloc_buf) + free(buf); + return l; +} + +static void reset_mp(zckMP *mp) { + if(mp->buffer) + free(mp->buffer); + memset(mp, 0, sizeof(zckMP)); +} + +size_t zck_multipart_get_boundary(zckDL *dl, char *b, size_t size) { + VALIDATE(dl); + if(dl->priv == NULL) + return 0; + + /* Create regex to find boundary */ + if(dl->priv->hdr_regex == NULL) { + char *regex = "boundary *= *([0-9a-fA-F]+)"; + dl->priv->hdr_regex = zmalloc(sizeof(regex_t)); + if(!create_regex(dl->priv->hdr_regex, regex)) + return 0; + } + + /* Copy buffer to null-terminated string because POSIX regex requires null- + * terminated string */ + char *buf = zmalloc(size+1); + if(buf == NULL) { + zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes for header\n", + size+1); + return 0; + } + buf[size] = '\0'; + memcpy(buf, b, size); + + /* Check whether this header contains the boundary and set it if it does */ + regmatch_t match[2] = {0}; + if(regexec(dl->priv->hdr_regex, buf, 2, match, 0) == 0) { + reset_mp(dl->priv->mp); + char *boundary = zmalloc(match[1].rm_eo - match[1].rm_so + 1); + memcpy(boundary, buf + match[1].rm_so, match[1].rm_eo - match[1].rm_so); + zck_log(ZCK_LOG_DEBUG, "Multipart boundary: %s\n", boundary); + dl->boundary = boundary; + } + if(buf) + free(buf); + return size; +} diff --git a/src/lib/zck_private.h b/src/lib/zck_private.h index 7246bb3..0b73675 100644 --- a/src/lib/zck_private.h +++ b/src/lib/zck_private.h @@ -47,7 +47,9 @@ typedef struct zckDLPriv { CURL *curl_ctx; zckMP *mp; int parser_started; + int is_chunk; regex_t *dl_regex; + regex_t *end_regex; regex_t *hdr_regex; } zckDLPriv; @@ -136,6 +138,13 @@ int zck_write_header(zckCtx *zck); char *zck_range_get_char(zckRange **range, int max_ranges); int zck_range_add(zckRangeInfo *info, zckIndex *idx, zckCtx *zck); +/* dl/multipart.c */ +size_t zck_multipart_extract(zckDL *dl, char *b, size_t l); +size_t zck_multipart_get_boundary(zckDL *dl, char *b, size_t size); + +/* dl/dl.c */ +int zck_dl_write_range(zckDL *dl, const char *at, size_t length); + /* log.c */ void zck_log(log_type lt, const char *format, ...); #endif diff --git a/src/zck_dl.c b/src/zck_dl.c index 614b13c..c0bd703 100644 --- a/src/zck_dl.c +++ b/src/zck_dl.c @@ -81,7 +81,7 @@ int main (int argc, char *argv[]) { exit(1); lseek(dl->dst_fd, 0, SEEK_SET); - if(!zck_dl_range(dl, argv[2])) + if(!zck_dl_range(dl, argv[2], 1)) exit(1); /* @@ -107,7 +107,7 @@ int main (int argc, char *argv[]) { default: break; } - zck_dl_free(dl); + zck_dl_free(&dl); zck_free(zck_tgt); zck_free(zck_src); zck_dl_global_cleanup(); -- 2.30.2